package com.java.basis.thread.n8.juc;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @author wangning
 * @create 2022-02-11 16:55
 */
@Slf4j(topic = "c.TestAqs")
public class TestAqs {
	public static void main(String[] args) {
		MyLock lock = new MyLock();
		new Thread(() -> {
			lock.lock();
			try {
				log.debug("locking...");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

			} finally {
				log.debug("unlock...");
				lock.unlock();
			}
		}, "t1").start();

		new Thread(() -> {
			lock.lock();
			try {
				log.debug("locking...");
			} finally {
				log.debug("unlock...");
				lock.unlock();
			}

		}, "t2").start();

	}

}

//自定义锁，不可重入锁
class MyLock implements Lock {

	//独占锁,同步器类
	class MySync extends AbstractQueuedSynchronizer {
		@Override
		protected boolean tryAcquire(int arg) {
			if (compareAndSetState(0, 1)) {
				//加上了锁,并设置 owner 为当前线程
				setExclusiveOwnerThread(Thread.currentThread());
				return true;
			}
			return false;
		}

		@Override
		protected boolean tryRelease(int arg) {
			setExclusiveOwnerThread(null);
			setState(0);
			return true;
		}

		//是否持有独占锁
		@Override
		protected boolean isHeldExclusively() {
			return getState() == 1;
		}

		public Condition newCondition() {
			return new ConditionObject();
		}
	}

	private MySync sync = new MySync();
	@Override //加锁
	public void lock() {
		sync.acquire(1);
	}

	@Override //加锁，可打断
	public void lockInterruptibly() throws InterruptedException {
		sync.acquireInterruptibly(1);

	}

	@Override //尝试加锁，只会尝试一次
	public boolean tryLock() {
		return sync.tryAcquire(1);
	}

	//尝试加锁，带超时的
	@Override
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		return sync.tryAcquireSharedNanos(1, unit.toNanos(time));
	}

	//解锁
	@Override
	public void unlock() {
		sync.release(1);
	}

	//创建条件变量
	@Override
	public Condition newCondition() {
		return sync.newCondition();
	}

}
